#include "StatusGrpcClient.h"

StatusConnectPool::StatusConnectPool(std::string host, std::string port, size_t pool_size)
	: m_host(host), m_port(port), m_pool_size(pool_size), m_b_stop(false)
{
	for (size_t i = 0; i < pool_size; ++i) {
		std::shared_ptr<grpc::Channel> channel = grpc::CreateChannel(host + ":" + port, grpc::InsecureChannelCredentials());
		m_connections.push(message::StatusService::NewStub(channel));
	}
}

StatusConnectPool::~StatusConnectPool()
{
	std::lock_guard<std::mutex> lock(m_mutex);
	Close();
	while (!m_connections.empty()) {
		m_connections.pop();
	}
}

std::unique_ptr<message::StatusService::Stub> StatusConnectPool::getConnection()
{
	std::unique_lock<std::mutex> lock(m_mutex);
	m_cond.wait(lock, [this]() {
		if (m_b_stop) {
			return true;
		}

		return !m_connections.empty();
	});

	if (m_b_stop) {
		return nullptr;
	}

	auto connection = std::move(m_connections.front());
	m_connections.pop();

	return connection;
}

void StatusConnectPool::returnConnection(std::unique_ptr<message::StatusService::Stub> connection)
{
	std::lock_guard<std::mutex> lock(m_mutex);
	if (m_b_stop) {
		return;
	}

	m_connections.push(std::move(connection));
	m_cond.notify_one();
}

void StatusConnectPool::Close()
{
	m_b_stop = true;
	m_cond.notify_all();
}

// 从状态服务器中获取聊天服务器信息（IP和token）
message::GetChatServerRsp StatusGrpcClient::getChatServer(int uid)
{
	grpc::ClientContext context;
	message::GetChatServerRsp reply;
	message::GetChatServerReq request;
	request.set_uid(uid);

	// 从GRPCConPool取出一个连接
	auto stub = m_pool->getConnection();
	grpc::Status status = stub->GetChatServer(&context, request, &reply);
	Defer defer([&stub, this]() {
		m_pool->returnConnection(std::move(stub));
	});
	if (status.ok()) {
		return reply;
	}
	else {
		reply.set_error(ErrorCodes::RPCFailed);
		return reply;
	}
}

StatusGrpcClient::StatusGrpcClient()
{
	auto& gCfgMgr = ConfigManager::getInstance();
	std::string host = gCfgMgr["StatusServer"]["Host"];
	std::string port = gCfgMgr["StatusServer"]["Port"];
	m_pool.reset(new StatusConnectPool(host, port, 5));
}
